﻿using System;
using System.Collections.Generic;
using System.Linq;
using Localization;
using SinBiota.Model.Business.MapServices.Datatypes;
using SinBiota.Model.Business.MapServices.Interfaces;
using SinBiota.Model.Business.PersistenceServices.Interfaces;
using SinBiota.Model.Entities;
using SinBiota.Model.Persistence.Repositories.Interfaces;

namespace SinBiota.Model.Business.PersistenceServices.Implementation
{
    public class OccurrencePersistenceServices : IOccurrencePersistenceServices
    {
        private readonly IOccurrenceRepository _occurrenceRepository;
        private readonly IKeywordPersistenceServices _keywordPersistence;
        private readonly IProjectPersistenceServices _projectPersistence;
        private readonly IMunicipalityPersistenceServices _municipalityPersistence;
        private readonly IConservationUnitPersistenceServices _conservationUnitPersistence;
        private readonly IHabitatPersistenceServices _habitatPersistence;
        private readonly IMicroHabitatPersistenceServices _microHabitatPersistence;
        private readonly IEcosystemPersistenceServices _ecosystemPersistence;
        private readonly IDrainageBasinPersistenceServices _drainageBasinPersistence;
        private readonly IUserPersistenceServices _userPersistenceServices;
        private readonly IOccurrenceAuthorRepository _occurrenceAuthorRepository;
        private readonly IMapDatabaseServices _mapDatabaseServices;
        private readonly ILocationPersistenceServices _locationPersistenceServices;
        private readonly IAquaticDataRepository _aquaticDataRepository;
        private readonly ISpecimenRepository _specimenRepository;
        private readonly ITaxonRepository _taxonRepository;

        public OccurrencePersistenceServices(IOccurrenceRepository occurrenceRepository, IKeywordPersistenceServices keywordPersistence, IProjectPersistenceServices projectPersistence, IMunicipalityPersistenceServices municipalityPersistence, IConservationUnitPersistenceServices conservationUnitPersistence, IHabitatPersistenceServices habitatPersistence, IMicroHabitatPersistenceServices microHabitatPersistence, IEcosystemPersistenceServices ecosystemPersistence, IDrainageBasinPersistenceServices drainageBasinPersistence, IUserPersistenceServices userPersistenceServices, IOccurrenceAuthorRepository occurrenceAuthorRepository, IMapDatabaseServices mapDatabaseServices, ILocationPersistenceServices locationPersistenceServices, IAquaticDataRepository aquaticDataRepository, ISpecimenRepository specimenRepository, ITaxonRepository taxonRepository)
        {
            _occurrenceRepository = occurrenceRepository;
            _taxonRepository = taxonRepository;
            _specimenRepository = specimenRepository;
            _aquaticDataRepository = aquaticDataRepository;
            _locationPersistenceServices = locationPersistenceServices;
            _mapDatabaseServices = mapDatabaseServices;
            _occurrenceAuthorRepository = occurrenceAuthorRepository;
            _userPersistenceServices = userPersistenceServices;
            _drainageBasinPersistence = drainageBasinPersistence;
            _ecosystemPersistence = ecosystemPersistence;
            _microHabitatPersistence = microHabitatPersistence;
            _habitatPersistence = habitatPersistence;
            _conservationUnitPersistence = conservationUnitPersistence;
            _municipalityPersistence = municipalityPersistence;
            _projectPersistence = projectPersistence;
            _keywordPersistence = keywordPersistence;
        }

        public Occurrence FindById(int id)
        {
            return _occurrenceRepository.FindById(id);
        }

        public IList<Occurrence> FindAll()
        {
            return _occurrenceRepository.FindAll();
        }

        public void Delete(Occurrence occurrence)
        {
            // Remove all children:

            _occurrenceRepository.Delete(occurrence);
        }
        public void DeleteById(int id)
        {
            Delete(FindById(id));
        }

        public void SaveOrUpdate(Occurrence occurrence, string username, int occurrenceAuthorId, int municipalityId, int conservationUnitId, int drainageBasinId, int[] ecosystemId, int[] habitatId, int[] microHabitatId, string[] keywordField)
        {
            //// Fetch entities from DB:
            occurrence.Author = _occurrenceAuthorRepository.FindById(occurrenceAuthorId);
            if (occurrence.Author == null) throw new InvalidOperationException(string.Format("{0}. Id:{1}. Type:{2}", Messages.EntityNotFound, occurrenceAuthorId, Strings.OccurrenceAuthor));

            // Update location:
            occurrence.Location.Municipality = _locationPersistenceServices.FindMunicipalityById(municipalityId);
            occurrence.Location.DrainageBasin = _locationPersistenceServices.FindDrainageBasinById(drainageBasinId);
            occurrence.Location.ConservationUnit = _locationPersistenceServices.FindConservationUnitById(conservationUnitId);

            //// Ecosystem:
            while (occurrence.Ecosystems.Count > 0) occurrence.Ecosystems.RemoveAt(0);
            if (ecosystemId != null) foreach (var id in ecosystemId) occurrence.Ecosystems.Add(_ecosystemPersistence.FindById(id));
            //// Habitat
            while (occurrence.Habitats.Count > 0) occurrence.Habitats.RemoveAt(0);
            if (habitatId != null) foreach (var id in habitatId) occurrence.Habitats.Add(_habitatPersistence.FindById(id));
            //// MicroHabitat
            while (occurrence.MicroHabitats.Count > 0) occurrence.MicroHabitats.RemoveAt(0);
            if (microHabitatId != null) foreach (var id in microHabitatId) occurrence.MicroHabitats.Add(_microHabitatPersistence.FindById(id));
            //// Keywords:
            while (occurrence.Keywords.Count > 0) occurrence.Keywords.RemoveAt(0);
            if (keywordField != null) foreach (var s in keywordField) occurrence.Keywords.Add(_keywordPersistence.FindByName(s) ?? new Keyword { Name = s });

            ////Aquatic Data: 
            if (occurrence.Location.Ambient == Ambient.Terrestrial)
            {
                occurrence.AquaticData = null;
            }

            // Method:
            if (occurrence.Method.Description == null) occurrence.Method.Description = "";

            // User:
            occurrence.User = _userPersistenceServices.FindByUsername(username);

            //// Update:
            _occurrenceRepository.SaveOrUpdate(occurrence);

       }

        //public void SaveSpeciesList(SpeciesList speciesList)
        //{
        //    _speciesListRepository.Save(speciesList);
        //}

        public Project FindProjectById(int id)
        {
            return _projectPersistence.FindById(id);
        }


        public IEnumerable<Occurrence> FindByAmbient(Ambient ambient)
        {
            return _occurrenceRepository.FindByAmbient(ambient);
        }

        public IEnumerable<Occurrence> FindByAuthorName(string name)
        {
            return _occurrenceRepository.FindByAuthorName(name);
        }

        public IEnumerable<Occurrence> FindByKeyword(string keyword)
        {
            return _occurrenceRepository.FindByKeyword(keyword);
        }

        public IEnumerable<Occurrence> FindByMunicipalityId(int municipalityId)
        {
            return _occurrenceRepository.FindByMunicipalityId(municipalityId);
        }

        public IEnumerable<Occurrence> FindByProjectCoordinator(string name)
        {
            return _occurrenceRepository.FindByProjectCoordinator(name);
        }

        public IEnumerable<Occurrence> FindByProjectMember(string name)
        {
            return _occurrenceRepository.FindByProjectMember(name);
        }

        public IEnumerable<Occurrence> FindByProjectId(int projectId)
        {
            return _occurrenceRepository.FindByProjectId(projectId);
        }

        public IEnumerable<Occurrence> FindByPublication(string name)
        {
            return _occurrenceRepository.FindByPublication(name);
        }

        public IEnumerable<Occurrence> FindByTaxonomicGroupId(int taxonomicGroupId)
        {
            return _occurrenceRepository.FindByTaxonomicGroupId(taxonomicGroupId);
        }

        public IEnumerable<Occurrence> FindByUsername(string username)
        {
            return _occurrenceRepository.FindByUsername(username);
        }

        public IEnumerable<Occurrence> FindByTaxon(string searchField)
        {
            return _occurrenceRepository.FindByTaxon(searchField);
        }

        public IEnumerable<LatLongWithId> GetOccurrencesByTaxon(string taxon)
        {
            return _mapDatabaseServices.GetOccurrencesByTaxon(taxon);
        }

        public IEnumerable<LegacyTaxonomicGroup> FindAllLegacyTaxonomicGroups()
        {
            return _occurrenceRepository.FindAllLegacyTaxonomicGroups();
        }

        public Specimen FindSpecimenById(int id)
        {
            return _specimenRepository.FindById(id);
        }

        public int NumberOfTaxonomicGroups()
        {
            return _occurrenceRepository.NumberOfTaxonomicGroups();
        }

        public IEnumerable<OccurrenceAuthor> FindAllOccurrenceAuthors()
        {
            return _occurrenceAuthorRepository.FindAll();
        }

        public int NumberOfAuthors()
        {
            return _occurrenceRepository.NumberOfAuthors();
        }

        public IDictionary<string , int> OccurrencesByAmbient()
        {
            return _occurrenceRepository.OccurrencesByAmbient();
        }

        public IDictionary<string, int> OccurrencesByDrainageBasin()
        {
            return _occurrenceRepository.OccurrencesByDrainageBasin();
        }

        public IDictionary<string, int> OccurrencesByMunicipality()
        {
            return _occurrenceRepository.OccurrencesByMunicipality();
        }

        public IDictionary<string, int> OccurrencesByConservationUnit()
        {
            return _occurrenceRepository.OccurrencesByConservationUnit();
        }

        public IDictionary<string, int> OccurrencesByTaxonomicGroup()
        {
            return _occurrenceRepository.OccurrencesByTaxonomicGroup();
        }

        public IDictionary<string, int> OccurrencesByMonthYear()
        {
            return _occurrenceRepository.OccurrencesByMonthYear();
        }

        public IDictionary<string, int> SpeciesByConservationUnit()
        {
            return _occurrenceRepository.SpecimensByConservationUnit();
        }

        public IDictionary<string, int> SpeciesByMunicipality()
        {
            return _occurrenceRepository.SpecimensByMunicipality();
        }

        public IDictionary<string, int> SpeciesByDrainageBasin()
        {
            return _occurrenceRepository.SpecimensByDrainageBasin();
        }

        public IDictionary<string, int> SpeciesByAmbient()
        {
            return _occurrenceRepository.SpecimensByAmbient();
        }

        public IDictionary<string, int> SpeciesByTaxonomicGroup()
        {
            return _occurrenceRepository.SpeciesByTaxonomicGroup();
        }

        public IDictionary<string, int> SpeciesByMonthYear()
        {
            return _occurrenceRepository.SpeciesByMonthYear();
        }

        public IDictionary<string, int> Top10Species()
        {
            return _occurrenceRepository.Top10Species();
        }

        public void IncludeOccurrencesInSpatialDatabase(IEnumerable<Occurrence> occurrences)
        {
            _mapDatabaseServices.IncludeOccurrencesInSpatialDatabase(occurrences);
        }

        public void InitOccurrenceSpatialDatabase()
        {
            _mapDatabaseServices.InitOccurrenceSpatialDatabase();

        }

        public void CreateAuthor(OccurrenceAuthor author)
        {
            _occurrenceAuthorRepository.Save(author);
        }

        public void DeleteSpecimen(Specimen specimen)
        {
            _specimenRepository.Delete(specimen);
        }

        public Taxon FindTaxonById(int taxonId)
        {
            return _taxonRepository.FindById(taxonId);
        }

        public void SaveSpecimen(Specimen specimen)
        {
            _specimenRepository.SaveOrUpdate(specimen);
        }

        public IEnumerable<Specimen> FindAllSpecimen()
        {
            return _specimenRepository.FindAll();
        }

        public IEnumerable<LatLongWithId> GetOccurrencesInSquare(double nwLat, double nwLong, double seLat, double seLong)
        {
            return _mapDatabaseServices.GetOccurrencesInSquare(new LatLong(nwLat, nwLong), new LatLong(seLat, seLong));
        }

    }
}